import {Msg} from "@/model/chat";

/**
 * 根据用户id生成IndexedDB的objectStore(相当于数据表)并将其返回，
 * 其中每一个数据库都存储了当前用户与另一位用户的聊天记录，
 * 当要操作聊天记录时发现没有对应的DB时就会触发升级并创建DB和objectStore
 * @param uid    当前登录账号的uid
 * @param fromUid 聊天记录的其中一个用户的id，与toId不存在先后顺序
 * @param toUid   聊天记录的其中一个用户的id，与fromId不存在先后顺序
 * @returns {Promise}
 */
export const store = (uid: string, fromUid: string, toUid: string): Promise<IDBDatabase | number> => {
    // 数据库名：`meetu_${当前登录账号id}_${fromUid}_${toUid}`
    const dbName =
        parseInt(fromUid) < parseInt(toUid)
            ? `meetu_${uid}_${fromUid}_${toUid}`
            : `meetu_${uid}_${toUid}_${fromUid}`;
    return new Promise((resolve, reject) => {
        const request = window.indexedDB.open(dbName, 1);
        request.onupgradeneeded = function (e) {
            console.log("数据库升级成功");
            const db = (e.target as any).result;
            if (!db.objectStoreNames.contains("message")) {
                const objectStore = db.createObjectStore("message", {
                    keyPath: "roomId",
                });
                objectStore.createIndex("fromUid", "fromUid", {unique: false});
                objectStore.createIndex("toUid", "toUid", {unique: false});
                objectStore.createIndex("createTime", "createTime", {unique: true});
            }
        };
        request.onerror = function (e) {
            console.log("打开数据库失败");
            reject(e.target);
        };
        request.onsuccess = function (e) {
            resolve((e.target as any).result);
        };
    });
};

/**
 * 缓存消息
 * @param uid
 * @param fromUid
 * @param toUid
 * @param obj
 */
export async function addMessage(uid: string, fromUid: string, toUid: string, obj: Msg) {
    const db: number | IDBDatabase = await store(uid, fromUid, toUid);
    const objectStore = (db as IDBDatabase)
        .transaction(["message"], "readwrite")
        .objectStore("message");
    return await new Promise((resolve) => {
        const request = objectStore.add({
            roomId: obj.roomId,
            fromUid: obj.fromUid,
            toUid: obj.toUid,
            message: obj.content,
            createTime: obj.createTime,
            status: obj.status,
        });
        request.onsuccess = (e) => {
            resolve(e.type);
        };
    });
}

/**
 * 清空某个用户的聊天记录
 * @param uid
 * @param fromUid
 * @param toUid
 */
export async function clearMessages(uid: string, fromUid: string, toUid: string) {
    const db: number | IDBDatabase = await store(uid, fromUid, toUid);
    const objectStore = (db as IDBDatabase)
        .transaction(["message"], "readwrite")
        .objectStore("message");
    objectStore.clear();
}

/**
 * 获取缓存消息
 * @param uid
 * @param fromUid
 * @param toUid
 */
export async function getAllMessages(uid: string, fromUid: string, toUid: string): Promise<any[]> {
    const db: number | IDBDatabase = await store(uid, fromUid, toUid);
    const objectStore = (db as IDBDatabase)
        .transaction(["message"], "readonly")
        .objectStore("message");
    const objectIndex = objectStore.index("createTime"); // 按照时间的先后顺序排列
    return await new Promise((resolve) => {
        const request = objectIndex.openCursor();
        const results: any[] = [];
        request.onsuccess = (e: Event) => {
            const cursor = (e.target as any).result;
            if (cursor) {
                results.push(cursor.value);
                cursor.continue();
            } else {
                // 所有的object都在results里面
                resolve(results);
            }
        };
    });
}

/**
 * 获取本地存储中的所有数据库，即当前用户的所有聊天记录
 * @param {String} uid 当前登录用户id
 * @returns {Promise<IDBDatabaseInfo[]>}
 */
export const getDatabases = async (uid: string): Promise<IDBDatabaseInfo[]> => {
    const dbs = window.indexedDB.databases
        ? await window.indexedDB.databases()
        : [];
    const pattern = new RegExp(`^meetu_${uid}_\\d+_\\d+$`);
    return dbs.filter((item) => pattern.test(item.name as string));
};

/**
 * 获取最后一条消息
 * @param uid
 * @param fromUid
 * @param toUid
 */
export async function getLastMessage(uid: string, fromUid: string, toUid: string): Promise<Msg[]> {
    const db: IDBDatabase | number = await store(uid, fromUid, toUid);
    const objectStore = (db as IDBDatabase)
        .transaction(["message"], "readonly")
        .objectStore("message");
    const objectIndex = objectStore.index("createTime");
    return await new Promise((resolve) => {
        const request = objectIndex.openCursor();
        const results: Msg[] = [];
        request.onsuccess = (e) => {
            const cursor = (e.target as any).result;
            if (cursor) {
                results.push(cursor.value);
                cursor.continue();
            } else {
                // 使用index索引查询默认会按照索引升序排序，取出数组中最后一项便是时间最新的记录
                resolve([results[results.length - 1]]);
            }
        };
    });
}

/**
 * 获取消息读取状态
 * @param uid
 * @param fromUid
 * @param toUid
 */
export async function getLastMsgReadStatus(uid: string, fromUid: string, toUid: string) {
    const lastMsg = await getLastMessage(uid, fromUid, toUid);
    return lastMsg[0].status;
}

/**
 * 更新消息读取状态
 * @param uid
 * @param roomId
 * @param fromUid
 * @param toUid
 * @param msg
 * @param createTime
 */
export async function putMessageReaded(uid: string, roomId: string,
                                       fromUid: string, toUid: string,
                                       msg: string, createTime: number): Promise<string> {
    const db: IDBDatabase | number = await store(uid, fromUid, toUid);
    const objectStore = (db as IDBDatabase)
        .transaction(["message"], "readwrite")
        .objectStore("message");
    return await new Promise((resolve) => {
        const request = objectStore.put({
            roomId: roomId,
            fromUid: fromUid,
            toUid: toUid,
            message: msg,
            createTime: createTime,
            hasRead: 1,
        });
        request.onsuccess = (e) => {
            resolve(e.type);
        };
    });
}

